1969(EDU div2)
A. Two Friends
莫诺卡普想开一个派对。他有
Monocarp 可以向朋友发送邀请。如果第
例如,如果
计算 Monocarp 至少要发出多少份邀请函,才能让至少
可以知道答案要么是
void solve() {
int n;cin >> n;vector<int> a(n + 1);map<int, int>mp;
for (int i = 1;i <= n;i++)cin >> a[i], mp[a[i]] = i;
int ok = 0;
for (int i = 1;i <= n;i++) {
for (int j = 1;j <= n;j++) {
if (a[i] == j && i == a[j])ok = 1;
}
}
if (ok)cout << 2 << "\n";
else cout << 3 << '\n';
}
B. Shifts and Sorting
让我们把某个字符串
您将得到一个二进制字符串
在一次操作中,您可以选择任意子串并循环移动它。这种操作的代价等于
您可以执行任意次数的给定操作。要使
#define int long long
void solve() {
string s;cin >> s;
int num1 = 0, ans = 0, ok = 0;
for (int i = 0;i < s.size();i++) {
if (s[i] == '1') {
num1++;ok = 1;
} else {
if (ok) ans += num1 + 1;
}
}
cout << ans << '\n';
}
C. Minimizing the Sum
给你一个长度为
可以执行以下操作:选择数组中的一个元素,并用其邻近元素的值替换它。
能执行上述操作最多
Solution
DP
贪心无法保证正确性,如:
4 2
4 2 1 2
可以知道
每次某数字进行操作只会影响身边的数字,这样操作最终影响的一定是一个连续的区间,且为了最优,在对区间进行操作时不会出现重叠的现象,因此最优的答案一定是对若干个不重叠的连续的区间进行修改,
对于每个这样的区间,有以下性质:
- 每个区间的操作次数就是区间长度减 1
- 这个区间中的所有元素都是
操作之前这个区间的最小值
#define int long long
void solve() {
int n, k;cin >> n >> k;vector<int> a(n + 1);
for (int i = 1;i <= n;i++)cin >> a[i];
vector<vector<int>> f(n + 1, vector<int>(k + 1, 1e18));
f[0][0] = 0;
for (int i = 1;i <= n;i++) {
int mi = a[i];
for (int j = 0;i + j <= n && j <= k;j++) {
mi = min(mi, a[i + j]);
for (int p = 0;p + j <= k;p++) {
f[i + j][p + j] = min(f[i + j][p + j], f[i - 1][p] + mi * (j + 1));
}
}
}
cout << *(min_element(f[n].begin(), f[n].end())) << '\n';
}
将小白月赛 92, CF (EDU 165) 补了,然后开始"DP,(图论 (LCA),数论 (常用))",然后开始板刷 CF~
(PS: 要考试的时候就优先突击考试)
官方题解:
void solve() {
int n, k;cin >> n >> k;
vector<ll> a(n);for (auto& x : a) cin >> x;
vector<vector<ll>> dp(n + 1, vector<ll>(k + 1, 1e18));
dp[0][0] = 0;
for (int i = 0; i < n; ++i) {
for (int j = 0; j <= k; ++j) {
ll mn = 1e18;
//从dp[i,j]->dp[i+d+1,j+d]在这之前已经进行了i个数字,j个操作,在该处操作了d次,区间长度为d+1,区间内全为mi
for (int d = 0; j + d <= k && i + d < n; ++d) {//d代表在此区间内的操作次数
mn = min(mn, a[i + d]);//这段区间内的最小值
dp[i + d + 1][j + d] = min(dp[i + d + 1][j + d], dp[i][j] + (d + 1) * mn);
}
}
}
cout << *min_element(dp[n].begin(), dp[n].end()) << '\n';//dp[n][min(k, n - 1)]
}
D. Shop Game
爱丽丝和鲍勃正在商店里玩游戏。商店里有
爱丽丝希望选择一个商品子集(可能是空)并购买它们。之后,Bob 会执行以下操作:
- 如果爱丽丝购买的物品少于
,鲍勃可以免费拿走所有物品; - 否则,他会免费拿走爱丽丝购买的
件(由鲍勃选择是哪一个 件),至于剩下的选择件,鲍勃会从爱丽丝那里购买,并为 /-th 件支付 。
爱丽丝的利润等于
爱丽丝希望自己的利润最大化,而鲍勃希望爱丽丝的利润最小化。您的任务是计算在爱丽丝和鲍勃都采取最优行动的情况下爱丽丝的利润。
Solution
堆/前缀和/思维
在这个题目中只有可能选择
若
Jiangly 代码:
void solve() {
int n, k;
cin >> n >> k;
vector<int> a(n), b(n);
for (int i = 0; i < n; i++) {
cin >> a[i];
}
for (int i = 0; i < n; i++) {
cin >> b[i];
}
vector<int> p(n);
iota(p.begin(), p.end(), 0);
sort(p.begin(), p.end(),
[&](int i, int j) {
return b[i] < b[j];
});
ll ans = 0;
vector<ll> profit(n + 1);
for (int i = 0; i < n; i++) {
profit[i + 1] = profit[i] + max(b[p[i]] - a[p[i]], 0);
}
ll sum = 0;
priority_queue<int> pq;
for (int i = n; i >= 0; i--) {
if (i < n) {
pq.push(a[p[i]]);
sum += a[p[i]];
}
while (pq.size() > k) {
sum -= pq.top();
pq.pop();
}
if (pq.size() == k) {
ans = max(ans, profit[i] - sum);
}
}
cout << ans << "\n";
}